from registers_descriptor import RegistersDescriptor
from basic_blocks import BasicBlocks
from final_code_exception import *
import re,time
from js_type import *

# important: R0 will be used as auxiliary register and where to store return variable

class FCG():
	def __init__(self,blockTable):
		self.interFilename = 'inter.3d'
		self.interLocs = None
		self.regDescriptor = RegistersDescriptor(9)
		self.basicBlocks = None
		self.blockTable = blockTable
		self.finalFilename = "final.ens"
		self.finalFd = None
		self.currentBtEntry = None
		self.finalLocs = []
		self.firstParam = True
		self.firstVariable = True
		self.firstTemporal = True

	def main(self):
		self.init()
		self.setInitFinalCode()
		self.genFinalCode()
		self.setEndingFinalCode()
		self.finish()


	def init(self):
		self.openICGFile()
		self.openFinalCodeFile()
		self.basicBlocks = BasicBlocks(self.interLocs,self.blockTable)
		self.basicBlocks.genBasicBlocks()

	def finish(self):
		try:
			for loc in self.finalLocs:
				self.finalFd.write(loc+"\n")
		except Exception,e:
			self.finalFd = None
			raise FinalCodeException("No se puede escribir el codigo final:"+str(e))
	
		try:
			self.finalFd.close()
		except Exception,e:
			raise FinalCodeException("No se puede cerrar el fichero de codigo final")

	def openICGFile(self):
		try:
			interFd = open(self.interFilename,"r")
			self.interLocs = interFd.readlines()
			interFd.close()
			for i in range(len(self.interLocs)):
				line = self.interLocs[i].replace("\n","")
				self.interLocs[i] = line


		except Exception,e:
			self.interFd = None
			print e

	def openFinalCodeFile(self):
		try:
			self.finalFd = open(self.finalFilename,"w")
		except Exception,e:
			self.finalFd = None

	def translate(self,loc):
		#DEBUG
		#print "translate: ",loc
		#FINDEBUG

		labelRe = re.compile("^.*:$")
		ifRe = re.compile("(IF )(.*)( GOTO )(.*)")
		gotoRe = re.compile("^GOTO.*")
		callRe = re.compile("^CALL.*")
		paramRe = re.compile("^PARAM.*")
		returnRe = re.compile("^RETURN.*")
		printRe = re.compile("^PRINT .*")
		readRe = re.compile("^READ .*")

		labelLoc = labelRe.search(loc)
		ifLoc = ifRe.search(loc)
		gotoLoc = gotoRe.search(loc)
		paramLoc = paramRe.search(loc)
		callLoc = callRe.search(loc)
		returnLoc = returnRe.search(loc)
		printLoc = printRe.search(loc)
		readLoc = readRe.search(loc)
	
		if (":=" in loc):
			return self.translateAssign(loc)
		elif (ifLoc != None):
			return self.translateIf(loc)
		elif (callLoc != None):
			return self.translateCall(loc)
		elif (gotoLoc != None):
			return self.translateGoto(loc)
		elif (labelLoc != None):
			return self.translateLabel(loc)
		elif (paramLoc != None):
			return self.translateParam(loc)
		elif (returnLoc != None):
			return self.translateReturn(loc)
		elif (printLoc != None):
			return self.translatePrint(loc)
		elif (readLoc != None):
			return self.translateRead(loc)
	
	def genFinalCode(self):
		self.currentBtEntry  = self.blockTable.getMainBlockTableEntry()
		btMainName = self.currentBtEntry.getName()
		firstMainLine = True #first line where globals and not inner function lines of source code are executed

		i = 0

		basicBlocks = self.basicBlocks.getBasicBlocks()


		for basicBlock in basicBlocks:
			finalBlockSaved = False

			#DEBUG
		#	for loc in basicBlock.getLocs():
		#		print "Basic Block loc:",loc['loc']
			#FINDEBUG

			for loc in basicBlock.getLocs():
				#DEBUG
#				print "--------------------------------------------------------LOC:",loc['loc']
				#FINDEBUG
				if (loc['btname'] == btMainName and firstMainLine and ("FUNCTION" not in loc['loc'])):
					self.finalLocs.append(";\n;\n;\n;"); # for a better reading
					self.finalLocs.append("INIT: NOP;inicio del programa")
					firstMainLine = False

				if ("GOTO" in loc['loc']):
					# if jump instruction, is last in basic block
					# and lexemes must be saved in stack before jump
					currentBtEntry = self.currentBtEntry

					self.finalLocs.append("; se salvan los registros del bloque basico antes salto para :"+currentBtEntry.getName())
					for i in range(1,self.regDescriptor.getSize()):
						register = "R"+str(i)
						stlocs = self.saveLexemesInRegister(register,True)
						for stloc in stlocs:
							self.finalLocs.append(stloc)
					finalBlockSaved = True
					self.finalLocs.append("; fin salvar registros bloque basico")

				finalLocs = self.translate(loc['loc'])
				self.finalLocs = self.finalLocs + finalLocs




			if ("END_FUNCTION" not in loc['loc'] and not finalBlockSaved):
				# after last loc is translated, values in registers must be saved
				currentBtEntry = self.currentBtEntry
				self.finalLocs.append("; se salvan los registros del bloque basico para :"+currentBtEntry.getName())
				for i in range(1,self.regDescriptor.getSize()):
					register = "R"+str(i)
					stlocs = self.saveLexemesInRegister(register,True)
					for stloc in stlocs:
						self.finalLocs.append(stloc)

				self.finalLocs.append("; fin salvar registros bloque basico")

			self.currentBtEntry = currentBtEntry


	def necessaryStore(self,lexeme,symbolTable,candidateRegister,resultLexeme=None):
		# algorithm page 548

		result = True

		addressDescriptor = symbolTable.getLocation(lexeme)

		#DEBUG
		#print "necessaryStore: addressDescriptor:",addressDescriptor
		#FINDEBUG

		if (addressDescriptor != "" and addressDescriptor != candidateRegister):
			# we are OK
			result = False
		elif lexeme == resultLexeme:
			result = False
		elif symbolTable.isAlive(lexeme) and symbolTable.getNextUse(lexeme) != None:
			result = False
		else:
			result = True

		return result

	def genLoadRA(self,lexeme):
		#this method stores in IY the address for RA_DYN (function or main) and returns the offset in the symbol table of lexeme 
		st = self.currentBtEntry.getSymbolTable()

		if (st.getPos(lexeme) == None):
			#lexeme is not in current ST
			father = self.currentBtEntry.getFather()

			# then it can only be in father which is main symbol table
			if(father == None):
				raise FinalCodeException("Lexeme:%s is not defined while generating final code"%lexeme)

			# lexeme address : PA(RA)
			st = father.getSymbolTable()

			self.finalLocs.append("MOVE /RA_MAIN,.IX; el lexema esta en MAIN")
			self.finalLocs.append("MOVE #4[.IX],.IY; IY <- dir de RA_DYN en MAIN")
		else:
			# lexeme is in current ST
			# offset for lexeme in ST is the same in RA
			# so, its address will be RA_DYN(currentRA) + st.offset
			# but remember, stack goes to decreased address
			# so SP is substracted
			self.finalLocs.append("MOVE /RA_DYN,.IY; IX <- dir de RA_DYN de la funcion actual")

		return st

	def getLexemeOffset(self,lexeme):
		
		attRe = re.compile("(.+)(\.)(.*)")
		attReRes = attRe.search(lexeme)

		if attReRes == None:
			st = self.genLoadRA(lexeme)
			offset = st.getOffset(lexeme)
		else:

			objLexeme = attReRes.group(1)	

			if (objLexeme == "this"):

				self.finalLocs.append("MOVE /CO,.IY; IX <- dir del objeto actual")

				st = self.currentBtEntry.getSymbolTable()
				offset = st.getOffset(lexeme)
			else:
				# lexeme = object.attribute

				location = self.currentBtEntry.getLocation(objLexeme)
				#DEBUG
				#print "OBJLEXEME LOCATION:",location
				#FINDEBUG

				regLocRe = re.compile("R\d")
				
				if regLocRe.match(location):
					#object addrress already in register
					self.finalLocs.append("MOVE .%s,.IY; IY <- la direccion del objeto"%location)
					st = self.currentBtEntry.getSymbolTable()

				else:

					st = self.genLoadRA(objLexeme)
					objOffset = st.getOffset(objLexeme)

					self.finalLocs.append("MOVE #%d[.IY],.IX; IX <- direccion del objeto"%objOffset)
					self.finalLocs.append("MOVE .IX,.IY; IY <- la direccion del objeto")

				newLexeme = "this."+attReRes.group(3)
				objSt = st.getType(objLexeme).getSymbolTable()
				offset = objSt.getOffset(newLexeme)


		return offset


	def genStoreIs(self,lexeme,candidateReg):
		self.finalLocs.append(";se generan las instrucciones para ST del lexema "+lexeme)		

		offset = self.getLexemeOffset(lexeme)

		self.finalLocs.append("MOVE %s,.IX; se carga en IX la direccion de comienzo de datos dinamicos del RA "%".IY")
		self.finalLocs.append("SUB .IX,#%s; desplazamiento del lexema:%s en RA"%(offset,lexeme))
		self.finalLocs.append("MOVE .A,.IX")
		self.finalLocs.append("MOVE .%s,[.IX];salva registro que contiene %s a memoria"%(candidateReg,lexeme))

		self.currentBtEntry.setLocation(lexeme,"memory")
			

	def saveLexemesInRegister(self,register,forced,resultLexeme=None):
		lexemes = self.regDescriptor.getLexemesInRegister(register)[:]
		locs = []

		for lexeme in lexemes:
			
			if forced:
				self.genStoreIs(lexeme,register)
				self.regDescriptor.removeLexemeFromRegister(register,lexeme)
			else:
				if (self.necessaryStore(lexeme,self.currentBtEntry.getSymbolTable(),register,resultLexeme)):
					self.genStoreIs(lexeme,register)
					self.regDescriptor.removeLexemeFromRegister(register,lexeme)
		return []

	def genLoadIs(self,register,lexeme,resultLexeme):
		locs = []							

		self.finalLocs.append(";se genera la carga en %s del lexema %s"%(register,lexeme))

		locs = locs + self.saveLexemesInRegister(register,False,resultLexeme)

		for loc  in locs:
			self.finalLocs.append(loc)

		offset = self.getLexemeOffset(lexeme)

		locs = []

		#loc = "MOVE %s,.IY; se carga en IY la direccion de "%"/RA_DYN"
		#locs.append(loc)
		loc = "MOVE %s,.IX; se carga en IX la direccion de comienzo de datos dinamicos del RA "%".IY"
		locs.append(loc)

		loc = "SUB .IX,#%s; desplazamiento del lexema:%s en RA"%(offset,lexeme)
		locs.append(loc)

		loc = "MOVE .A,.IX"
		locs.append(loc)
		loc = "MOVE [.IX],.%s;load registro para lexema:%s"%(register,lexeme)
		locs.append(loc)

		for loc  in locs:
			self.finalLocs.append(loc)

		self.regDescriptor.addInRegister(register,lexeme)
		self.currentBtEntry.setLocation(lexeme,register)
		#DEBUG
		#print "GEN LOAD IS"
		#print "Lexeme:%s location:%s"%(lexeme,register)
		#print "Lexeme:%s location:%s"%(lexeme,self.currentBtEntry.getLocation(lexeme))
		#FINDEBUG

		return []

	def selectReg(self,lexeme):
		register = self.regDescriptor.lexemeInRegister(lexeme)
		if(register != None):
			#lexeme already in register, then do nothing
			register = None
		else:
			register = self.regDescriptor.getNextCandidate()
			#DEBUG
			#print "next candidate:%s"%register
			#FINDEBUG

		return register

	def getRegForLexeme(self,lexeme):
		#return register where lexeme is or get a new one y not loaded yet

		#load y
		register = self.selectReg(lexeme)
		if register != None:
			# not already in register
			# first of all, all lexemes in this register must be saved in stack
			# and then load lexeme in register
			finalCodeLocs = self.genLoadIs(register,lexeme,None)

			for finalCodeLoc in finalCodeLocs:
				self.finalLocs.append(finalCodeLoc)
		else:
			register = self.currentBtEntry.getLocation(lexeme)
		return register


	def getReg(self,loc):
		'''loc must be a three address assigment instruction'''

		# currentAR : memory address for current RA


		#DEBUG
		#print "GETREG LOC:",loc
		#FINDEBUG

		finalCodeLocs = []

		terms = loc.split()

		rhLoc = "" #right hand loc

		if len(terms) > 2:

			for i in range(2,len(terms)):
				rhLoc += terms[i] + " "
			rhLoc = rhLoc[:-1]

		regRe = re.compile("^[CALL|'|\d]")
		memAllocRe = re.compile("NEW CALL .*") # object constructor

		if terms[1] == ":=":
			# if assign
			rhExprLength = len(terms) -2 #right hand expression length
		else:
			rhExprLength = 0

		#DEBUG
		#print "----------------------------------------------------------"
		#print "rhExprLength:",rhExprLength
		#print "----------------------------------------------------------"
		#FINDEBUG

		if (rhExprLength == 3):

			if memAllocRe.search(rhLoc) == None:
				# x = y op z

				#load y
				yRegister = self.selectReg(terms[2])
				if yRegister != None:
					# not already in register
					# first of all, all lexemes in this register must be saved in stack
					# and then load lexeme in register
					finalCodeLocs += self.genLoadIs(yRegister,terms[2],terms[0])

				#load z
				zRegister = self.selectReg(terms[4])
				if zRegister != None:
					# not already in register
					# first of all, all lexemes in this register must be saved in stack
					# and then load lexeme in register
					finalCodeLocs += self.genLoadIs(zRegister,terms[4],terms[0])

				#load x
				xRegister = self.selectReg(terms[0])
				if xRegister != None:
					# not already in register
					# first of all, all lexemes in this register must be saved in stack
					# and then load lexeme in register
					finalCodeLocs += self.genLoadIs(xRegister,terms[0],terms[0])
			else:
				#manage loc as common CALL
				# only x register must be located
				xRegister = self.selectReg(terms[0])
				if xRegister != None:
					# not already in register
					# first of all, all lexemes in this register must be saved in stack
					# and then load lexeme in register
					finalCodeLocs += self.genLoadIs(xRegister,terms[0],terms[0])

		#elif (len(terms) == 4):
		elif (rhExprLength == 2 and regRe.search(rhLoc) == None):
			# x = op y 

			#load y
			yRegister = self.selectReg(terms[3])
			if yRegister != None:
				# not already in register
				# first of all, all lexemes in this register must be saved in stack
				# and then load lexeme in register
				finalCodeLocs += self.genLoadIs(yRegister,terms[3],terms[0])

			#load x
			xRegister = self.selectReg(terms[0])
			if xRegister != None:
				# not already in register
				# first of all, all lexemes in this register must be saved in stack
				# and then load lexeme in register
				finalCodeLocs += self.genLoadIs(xRegister,terms[0],terms[0])

		#elif (len(terms) == 3):
		elif (rhExprLength == 2):
			# x = CALL function,nparams
			# only x register must be located
			xRegister = self.selectReg(terms[0])
			if xRegister != None:
				# not already in register
				# first of all, all lexemes in this register must be saved in stack
				# and then load lexeme in register
				finalCodeLocs += self.genLoadIs(xRegister,terms[0],terms[0])

		elif (rhExprLength == 1):
			# copy ins
			# x = y
			# with y = { lexeme, number, string}

			if regRe.search(rhLoc) == None:
				# x = y
				yRegister = self.selectReg(terms[2])
				if yRegister != None:
					# not already in register
					# first of all, all lexemes in this register must be saved in stack
					# and then load lexeme in register
					finalCodeLocs += self.genLoadIs(yRegister,terms[2],terms[0])

				#location for y is yRegister and also x is yRegister
				yRegister = self.currentBtEntry.getLocation(terms[2])
				self.regDescriptor.addInRegister(yRegister,terms[0])
				self.currentBtEntry.setLocation(terms[0],yRegister)
			
			else:
				#x = {number, string, call}
				# only x register must be located
				xRegister = self.selectReg(terms[0])
				if xRegister != None:
					# not already in register
					# first of all, all lexemes in this register must be saved in stack
					# and then load lexeme in register
					finalCodeLocs += self.genLoadIs(xRegister,terms[0],terms[0])

		else:
			#RETURN X
			#READ X
			#PRINT X
			xRegister = self.selectReg(terms[1])
			if xRegister != None:
				# not already in register
				# first of all, all lexemes in this register must be saved in stack
				# and then load lexeme in register
				#finalCodeLocs += self.genLoadIs(xRegister,terms[0],terms[0])
				#DEBUG
				#print "..........................................................."
				#print loc
				#print "TERMS[0]:",terms[0]
				#print "POS:",self.currentBtEntry.getSymbolTable().getPos(terms[1])
				#print "..........................................................."
				#DEBUG
				finalCodeLocs += self.genLoadIs(xRegister,terms[1],None)

	
		return finalCodeLocs

	def translateLabel(self,loc):
		defFunctionRe = re.compile("(^FUNCTION_)(.*)(:)")
		endFunctionRe = re.compile("(^END_FUNCTION_)(.*)(:)")

		defFunction = defFunctionRe.search(loc)
		endFunction = endFunctionRe.search(loc)

		if (defFunction != None):
			# begining of a function

			self.currentBtEntry = self.blockTable.getBlockTableEntry(defFunction.group(2))
			self.finalLocs.append(loc+" NOP") #if begin function, FUNCTION_*:NOP must be set first 
			loc = ""
			self.finalLocs.append("POP .R0") # R0 <-- RET
			self.finalLocs.append("MOVE .R0,/RA_RET; RA_RET apunta a la direccion de retorno")
			self.finalLocs.append("MOVE /RA_INIT,.IX")
			self.finalLocs.append("MOVE /RA_RET,#-3[.IX]; se indica en el RA la direccion de retorno")

			symbolTable = self.currentBtEntry.getSymbolTable()

			raSize = symbolTable.getRaSize()
			paramSize = symbolTable.getParamsSize()

			#remember, params are already set in stack

			#DEBUG
			#print "------------------------------------------------------------"
			#print "raSize:",raSize
			#print "paramSize:",paramSize
			#print "------------------------------------------------------------"
			#FINDEBUG

			#raSize is in bytes but a word is two bytes long
			#for i in range ((raSize -paramSize)/ 2):
			for i in range ((raSize -paramSize)):
				self.finalLocs.append("PUSH #0")


		elif (endFunction != None):
			#ending function

			# restore pointers and registers
			symbolTable = self.currentBtEntry.getSymbolTable()

			#DEBUG
			#print "translateLabel: END FUNCTION st:",symbolTable.getName()
			#FINDEBUG

			raSize = symbolTable.getRaSize()

			self.finalLocs.append(loc+"NOP")

			#raSize is in bytes but a word is two bytes long
			#for i in range (raSize / 2):
			for i in range (raSize):
				self.finalLocs.append("POP .R0")
			
			
			for i in range(1,10):
				stlocs = self.saveLexemesInRegister("R%d"%i,True)
				for stloc in stlocs:
					self.finalLocs.append(stloc)

			#self.finalLocs.append("POP .RO; R0 <- RET")
			self.finalLocs.append("POP .IY; IY <- RET")
			self.finalLocs.append("POP .R0; R0 <- RV")
			self.finalLocs.append("POP .SR; se restaura SR")
			self.finalLocs.append("POP /RA_INIT; se restaura el RA del llamante")
			self.finalLocs.append("MOVE /RA_INIT,.IX; IX <- /RA_INIT")
			#self.finalLocs.append("MOVE [.IX],/RA_CUR; RA_CUR es ahora el llamante")
			self.finalLocs.append("MOVE .IX,/RA_CUR; RA_CUR es ahora el llamante")
			self.finalLocs.append("SUB .IX,#4")
			self.finalLocs.append("MOVE .A,/RA_DYN; se restaura RA_DYN")

			self.restoreRegistersInStack()
			#self.finalLocs.append("MOVE /RA_RET,.R0")
			self.finalLocs.append("MOVE .IY,.R0")
			self.finalLocs.append("PUSH .R0; se prepara para la instruccion RET")

			self.currentBtEntry = self.blockTable.getMainBlockTableEntry()

			self.finalLocs.append("RET")
			loc = ""

		#just normal label

		return [loc + "NOP"]

	
	def translateParam(self,loc):
		# loc = PARAM X

		locs = []

		if self.firstParam: # if first we must set RA_PARAM
			self.saveRegistersInStack()
			#self.finalLocs.append("ADD .SP,#1;primera pos libre en la pila")
	
			self.finalLocs.append("MOVE /RA_INIT,.IX; se guarda en IX la dir de inicio del RA llamante")
			self.finalLocs.append("MOVE .SP,/RA_INIT;se inicializa el RA")
			self.finalLocs.append("MOVE .SP,/RA_CUR;")
			self.finalLocs.append("PUSH .IX; se guarda en la pila el inicio del RA del llamante");
			self.finalLocs.append("PUSH .SR; se salva el registro de estado")
			self.finalLocs.append("PUSH #0; se reserva espacio para el valor devuelto")
			self.finalLocs.append("PUSH #0; se reserva espacio para la direccion de retorno")

			#self.finalLocs.append("ADD .SP,#1")
			self.finalLocs.append("MOVE .SP,/RA_DYN; se inicializa el puntero de variables y temporales")
			self.firstParam = False

		(param,x) = loc.split()
		#param must be load in a register
		locs = self.getReg(loc)
		for loc in locs:
			self.finalLocs.append(loc)
		
		rx = self.currentBtEntry.getLocation(x)

		self.finalLocs.append("PUSH .%s; se salva en pila el parametro"%rx)
		return []

	
	def translateReturn(self,loc):
		# loc = RETURN lexeme
		(returnTerm,lexeme) = loc.split()

		#offset = self.getLexemeOffset(lexeme)
		
		commLoc = ";return %s"%lexeme
		self.finalLocs.append(commLoc)

		register = self.currentBtEntry.getLocation(lexeme)

		regLocRe = re.compile("R\d")
		
		if regLocRe.match(register) == None:
			# lexeme is in memory
			self.getReg(loc)
			register = self.currentBtEntry.getLocation(lexeme)
			#print "*****************************************"
			#print "TRANSLATE RETURN. register:%s"%register
			#print "*****************************************"
		
		loc = "MOVE .%s,.R0;load R0 con el valor devuelto por lexema:%s"%(register,lexeme)
		self.finalLocs.append(loc)

		functionName = self.currentBtEntry.getName()

		#lexeme must be store in return value in RA
		# Return value is stored in third position
		self.finalLocs.append("MOVE .R0,/RV; RA(VD) <- R0")
		self.finalLocs.append("BR /END_FUNCTION_%s"%functionName)

		return []

	
	def translatePrint(self,loc):
		(printTerm,lexeme) = loc.split()

		register = self.currentBtEntry.getLocation(lexeme)

		regLocRe = re.compile("R\d")
		
		if regLocRe.match(register) == None:
			# lexeme is in memory
			self.getReg(loc)
			register = self.currentBtEntry.getLocation(lexeme)

		lexemeType = None
		
		if "." in lexeme:
			(lterm,rterm) = lexeme.split(".")

			objType = self.currentBtEntry.getType(lterm)
			if isinstance(objType,ObjectType):
				st = objType.getSymbolTable()
				lexemeType = st.getType("this."+rterm)
		else:
			lexemeType = self.currentBtEntry.getType(lexeme)
		
		if isinstance(lexemeType,IntegerType) or isinstance(lexemeType,BooleanType):
			self.finalLocs.append("WRINT .%s"%register)

		elif isinstance(lexemeType,StringType):
			self.finalLocs.append("WRINT [.%s]"%register)


		return []

	def translateRead(self,loc):
		(readTerm,lexeme) = loc.split()

		location = self.currentBtEntry.getLocation(lexeme)
		register = location

		#print "POS:",self.currentBtEntry.getSymbolTable().getPos(lexeme)

		if (location == None or "mem" in location or location == ""):
			self.getReg(loc)
			register = self.currentBtEntry.getLocation(lexeme)

		self.finalLocs.append("ININT .%s"%register)
		return []

	def translateAssign(self,loc):
		numberRe = re.compile("^\d*$")
		stringRe = re.compile("^'")
		memAllocRe = re.compile("NEW CALL .*") # object constructor
		callRe = re.compile("CALL.*,")

		locs = self.getReg(loc)

		terms = loc.split()

		rhLoc = "" #right hand loc

		for i in range(2,len(terms)):
			rhLoc += terms[i] + " "

		rhLoc = rhLoc[:-1]

		#DEBUG
		#print "-------------------------------------"
		#print "rhLoc",rhLoc
		#print "-------------------------------------"
		#FINDEBUG

		rhExprLength = len(terms) -2

		#if (len(terms) == 5):
		if (rhExprLength == 3):
			if memAllocRe.search(rhLoc) == None:
				# x = y op z
				op = terms[3]
				rx = self.currentBtEntry.getLocation(terms[0])
				ry = self.currentBtEntry.getLocation(terms[2])
				rz = self.currentBtEntry.getLocation(terms[4])

				if (op == "+"):
					locs.append("ADD .%s, .%s  ;y+z. La suma se guarda en A"%(ry,rz))
            				locs.append("BNV /NdesbAdd      ; Salta a Ndesb si no hay desbordamiento en la suma")
            				locs.append("WRSTR /Desbord; Escribe en consola la cadena Desbordamiento")
            				locs.append ("HALT ;detiene la ejecucion por error de desbordamiento")
					locs.append("NdesbAdd: NOP")
            				locs.append("MOVE .A, .%s    ; Guardamos el resultado y+z en x" %rx)

				elif (op == "*"):
					locs.append("MUL .%s, .%s  ;y+z. La suma se guarda en A"%(ry,rz))
            				locs.append("BNV /NdesbMul      ; Salta a Ndesb si no hay desbordamiento en la suma")
            				locs.append("WRSTR /Desbord; Escribe en consola la cadena Desbordamiento")
            				locs.append ("HALT ;detiene la ejecucion por error de desbordamiento")
					locs.append("NdesbMul: NOP")
            				locs.append("MOVE .A, .%s    ; Guardamos el resultado y+z en x" %rx)

			else:
				#constructor called
				locs += self.translateCall(loc)
			
		#elif (len(terms) == 4):
		elif (rhExprLength == 2 and callRe.search(loc) == None ):
			# x = op y
			# op = -

			rx = self.currentBtEntry.getLocation(terms[0])
			ry = self.currentBtEntry.getLocation(terms[2])

			locs.append("SUB #0,.%s; 0 - y para hacerlo negativo"%ry)
            		locs.append("BNV Ndesb      ; Salta a Ndesb si no hay desbordamiento en la suma")
            		locs.append("WRSTR Desbord; Escribe en consola la cadena Desbordamiento")
            		locs.append ("HALT ;detiene la ejecucion por error de desbordamiento")
			locs.append("Ndesb: NOP")
			locs.append("MOVE .A,.%s; x = - y"%rx)

		else:
			#DEBUG
			#print terms
			#FINDEBUG

			# copy ins
			# x = y
			# with y = { lexeme, call, number, string}

			
			rhLoc = "" #right hand loc

			for i in range(2,len(terms)):
				rhLoc += terms[i] + " "

			rhLoc = rhLoc[:-1]

		
			rx = self.currentBtEntry.getLocation(terms[0])
			if numberRe.match(terms[2]):
				# x = num
				locs += self.genLoadNumber(rx,int(terms[2]))
			elif stringRe.match(terms[2]):
				# x = string
				locs += self.genLoadString(rx,terms[2])
			elif callRe.search(rhLoc) != None:
				locs += self.translateCall(loc)
		return locs
	
	def translateCall(self,loc):
		self.firstParam = True
		locs = []
		#DEBUG
		#print loc
		#FINDEBUG

		# CHECK nParams == symbolTable.getNumberParams

		register = None
		lexeme = None
		constructor = False

		memAllocRe = re.compile('(.*) (:=) (NEW CALL) (.*),(\d)')
		memAllocVoidRe = re.compile('(NEW CALL) (.*),(\d)')

		callRe = re.compile('(.*) (:=) (CALL) (.*),(\d)')
		callVoidRe = re.compile('(CALL) (.*),(\d)')

		if(memAllocRe.match(loc)):
			data = memAllocRe.match(loc)
			lexeme = data.group(1)
			functionName = data.group(4)
			nParams = int(data.group(5))
			register = self.currentBtEntry.getLocation(data.group(1))
			constructor = True

		elif(memAllocVoidRe.match(loc)):
			data = memAllocVoidRe.match(loc)

			functionName = data.group(2)
			nParams = int(data.group(3))

		elif(callRe.match(loc)):
			data = callRe.match(loc)

			lexeme = data.group(1)
			functionName = data.group(4)
			nParams = int(data.group(5))
			register = self.currentBtEntry.getLocation(data.group(1))
		else:
			data = callVoidRe.match(loc)

			functionName = data.group(2)
			nParams = int(data.group(3))

		btEntry = self.blockTable.getBlockTableEntry(functionName)
		
		if btEntry == None:
			raise FinalCodeException("No se puede escribir el codigo final:la funcion %s no esta definida"%(functionName))

		symbolTable = btEntry.getSymbolTable()

		if nParams != symbolTable.getParamsLength():
			raise FinalCodeException("No se puede escribir el codigo final:la funcion %s espera %d parametros y se pasan %d"%(functionName,symbolTable.getParamsLength(),nParams))
		
		# in intermediate and final code, functions start with FUNCTION_
		functionName = "FUNCTION_"+functionName

		return self.genCall(functionName,register,lexeme,constructor)

	def translateIf(self,loc):
		ifRe = re.compile("(IF )(.*)( GOTO )(.*)")
		numRe = re.compile("\d")
		
		ifReRes = ifRe.search(loc)

		condition = ifReRes.group(2)
		label = ifReRes.group(4)

		terms = condition.split()

		term1 = terms[0]

		if len(terms) > 1:

			op = terms[1]
			term2 = terms[2]
		else:
			# loc = if (a) , so condition is a != 0 for jumping
			op = "!="
			term2 = "0"

		if numRe.match(term1) != None:
			xterm = "#"+term1
		else:
			xterm = "."+self.getRegForLexeme(term1)

		if numRe.match(term2) != None:
			yterm = "#"+term2
		else:
			yterm = "."+self.getRegForLexeme(term2)

		
		self.finalLocs.append("CMP %s,%s"%(xterm,yterm))
		#op can only be "=" or "<"
		if op == "=":
			self.finalLocs.append("BZ /%s"%label)
		elif op == "!=":
			self.finalLocs.append("BNZ /%s"%label)
		elif op == "<":
			self.finalLocs.append("BN /%s"%label)
		else:
			raise FinalCodeException("No se puede escribir el codigo final:"+"La condicion para la sentencia IF no es < o ==")
			
		
		return []

	def translateGoto(self,loc):
		(op,label) = loc.split()
		label = label.replace(":","")
		return ["BR /%s"%label]


	def genLoadNumber(self,register,number):
		locs = []
		loc = "MOVE #%d,.%s;se carga en %s un numero"%(number,register,register)
		locs.append(loc)
		return locs

	def genLoadString(self,register,string):
		locs = []

		addrLabel = "addrstr_"+str(time.time())+str(len(string))
		addrLabel = addrLabel.replace(".","")
		length = len(string)
		string = string + " " #blank will be changed to \0

		addrLabel="addrStr_"

		# esto solo funciona con Windows
		locs.append(';%s: DATA "%s"'%(addrLabel,string.replace("'",""))) #Diana, descomenta esta linea y las 3 siguientes
		locs.append(";MOVE /%s,.%s; registro contiene la direccion del string"%(addrLabel,register))
		locs.append(";MOVE /%s,.IX"%(addrLabel))
		locs.append(";MOVE #0,#%d[.IX]"%(length))
		#
		return locs

	def setInitFinalCode(self):
		self.finalLocs.append(";pila configurada hacia direcciones decrecientes")

		# Set initial values for SP, RA_INIT and current RA (RA_CUR)
		self.finalLocs.append("ORG 0")
		self.finalLocs.append("RA_PARAM_SZ: EQU 4")
		self.finalLocs.append("Desbord: EQU 4") #Diana, esto no lo descomentes
		self.finalLocs.append(';Desbord: DATA "Error por desbordamiento en op. aritmetica"') #Diana Descomenta este
		self.finalLocs.append("MOVE #65535,.SP;puntero de pila en la cima de la memoria")

		self.finalLocs.append("RA_MAIN: RES 1")
		self.finalLocs.append("RA_CUR: RES 1")
		# RA_CUR is an address memory to store current RA pointer
		self.finalLocs.append("RA_INIT: RES 1")
		# RA_INIT is an address memory to store main RA init
		#self.finalLocs.append("RA_PARAM: RES 1")
		# RA_PARAM points to init params
		self.finalLocs.append("RA_RET: RES 1")
		# RA_RET points to return address
		self.finalLocs.append("RA_DYN: RES 1")
		# RA_DYN point to dynamic content : variables + temporals as in symbol table
		self.finalLocs.append("RV: RES 1")
		# Used to store return value
		self.finalLocs.append("CO: RES 1")
		# Used to store address for current object


		self.finalLocs.append("MOVE .SP, /RA_INIT")
		self.finalLocs.append("MOVE .SP, /RA_MAIN")
		self.finalLocs.append("MOVE .SP, /RA_CUR")
		
		self.finalLocs.append("PUSH #0;RA_INIT del llamante es null en MAIN")
		self.finalLocs.append("PUSH .SR;SR en MAIN")
		self.finalLocs.append("PUSH #0;Valor Devuelto es null en MAIN")
		self.finalLocs.append("PUSH #0;RET es null en MAIN")

		self.finalLocs.append("MOVE .SP, /RA_DYN; main no tiene parametros asi que apunta al inicio")

		#start program
		self.finalLocs.append("BR /INIT;salto a inicio del programa")
		self.finalLocs.append(";\n;\n;\n;"); # for a better reading


	def genCall(self,functionName,register,lexeme,constructor):
		locs = []

		if(constructor):
			size = self.currentBtEntry.getType(lexeme).getObjectSize()

			labelName = lexeme.replace(".","")
			locs.append("addr_%s: RES %s"%(lexeme.replace(".",""),size))
			locs.append("MOVE #addr_%s,/CO;se indica en current object la dir actual del objeto"%(lexeme.replace(".","")))

		locs.append("CALL /%s"%functionName)

		if (constructor and register != None):
			
			locs.append("MOVE /CO,.%s;se salva en el registro la direccion del objeto"%register)
		else:
			if (register != None):
				locs.append("MOVE /RV,.%s;se obtiene el valor devuelto"%register)
		return locs

	def setEndingFinalCode(self):
		self.finalLocs.append("HALT")
		self.finalLocs.append("END;fin del programa")

	def saveRegistersInStack(self):
		for i in range(1,self.regDescriptor.getSize()+1):
		#for i in range(1,self.regDescriptor.getSize()):
			self.finalLocs.append("PUSH .R%s"%i)

	def restoreRegistersInStack(self):
		for i in range(self.regDescriptor.getSize(),0,-1):
		#for i in range(self.regDescriptor.getSize(),0,-1):
			self.finalLocs.append("POP .R%s"%i)

	def setRaInStack(self,symbolTable):
		locs = []

		locs.append("PUSH .SR; se salva el registro de estado")
		#TODO set RA structure
		locs.append("MOVE .SP,/RA_CUR; RA_CUR <- inicio RA")

		for stEntry in symbolTable.getSymbolTableEntries():
			locs.append("MOVE .#0,.R0;se inicializa R0")
			if not isinstance(stEntry.getType(),FunctionType):
				locs.append("PUSH .R0;se prepara el espacio en RA para:%s"%stEntry.getLexeme())


